#pragma once

#include "SkeletonNode.h"

#include <vector>
#include <map>
#include "Transform.h"
#include "Animation.h"

class ShaderMaterial;



/**
* Objects of this class can calculate the transformation matrices
* for every bone (by using a hierarchical structure).
* This class can also display the collection of bones that form
* a skeleton
*/
class Skeleton:public FXValue
{
public:
	

	/**
	* Creates a new Skeleton object
	*/
	Skeleton(void);
	/**
	* Destroys the Skeleton object.
	*/
	virtual ~Skeleton(void);
	/**
	* Sets the material to use for the Skeleton.
	* @param material the material to use.
	*/
	void SetMaterial(ShaderMaterial* material);
	/**
	* Adds a root bone to this skeleton.
	* @param node the node to add. The tree will be walked
	* to ensure to add all the nodes to the map.
	* as value.
	*/
	void AddRoot(SkeletonNode* node);
	/**
	* Returns a SkeletonNode object with a specific name, or NULL
	* if the node is not found.
	* @param name the name for the bone.
	* @return the skeleton node.
	*/
	SkeletonNode* GetSkeletonNode(wstring name);
	/**
	* Sets an animation as the current animation for
	* this skeletion.
	* @param animation the animation to set.
	*/
	void SetAnimation(Animation* animation);
	/**
	* Add an animation to this skeleton
	* @param animation the animation add.
	*/
	void AddAnimation(Animation* animation);
	/**
	* Add an animation to this skeleton
	* @param animation the animation add.
	*/
	void AddAnimation(AnimationPtr animation);
	/**
	* Creates a copy of the initial pose of the skeleton as an animation.
	* This is useful if you want to create animations with the help of
	* sensors for example.
	*/ 
	Animation* CopyInitialPoseToAnimation();

	/**
	* Activates an animation.
	* @param name the name for the animation.
	* @param looping set this parameter to false if you want show the 
	* animation only once.
	*/
	void ActivateAnimation(tstring name,bool looping=true);
	/**
	* Check if an animation is playing at the moment.
	* @return true if the animation is playing , false otherwise.
	*/
	bool IsAnimationPlaying(){
		if ( m_pAnimation== NULL)
			return false;
		return m_Looping  || 
			m_AnimationTime < m_pAnimation->GetStopFrame();
	}
	/**
	* Returns the animation that is currently in use.
	* @return the used animation
	*/
	Animation* GetAnimation(){
		return m_pAnimation;
	}
	/**
	* Calculates all the matrices needed for the
	* animation.
	* @param time the animation time (between start and stop frame of the animation).
	*/
	void Animate(float time);
	/**
	* Sets the bone matrix for a bone id. (bone ids are one based)
	* @param id the id for the bone.
	* @param transform a pointer to the transform object.
	*/
	void SetBoneMatrix(int id, DAEMatrix& matrix);
	/**
	* Calculate the local transformations for each node. These local transformations can
	* be used to animate a bone with a controller.
	*/
	void CalculateLocalTransformations();

	/**
	* Returns the size of the value in bytes.
	* @return the size in bytes.
	*/
	int GetSizeInBytes()const{
		return sizeof(float)*16*40;//m_NodeMap.size();
	}
	/**
	* Returns the pointer to the beginning of the value.
	* @return a void pointer to the beginning of the value.
	*/
	const void* GetValuePointer()const{
		return m_BoneMatrices;
	}
	/**
	* Returns the file location of this skeleton.
	* @return the location of the file that defines this skeleton.
	*/
	tstring& GetFileLocation(){return m_FileLocation;}
	/**
	* Sets the file location for this skeleton.
	* @param fileLocation the file location for this skeleton.
	*/
	void SetFileLocation(tstring& location){m_FileLocation=location;}

	/**
	* Create a copy of the skeleton.
	* @return a copy of the skeleton
	*/
	Skeleton* Clone() const;
private:
	/**
	* Add the children of a node to the map of nodes.
	* @param node the node to analyze.
	*/
	void AddNodeChildren(SkeletonNode* node);
	/**
	* The location of the skeleton file (for reload)
	* purposes.
	*/
	tstring m_FileLocation;
	/**
	* The material to draw the skeleton with.
	*/
	ShaderMaterial* m_pMaterial;
	/**
	* The root nodes of the skeleton.
	*/
	vector<SkeletonNode*> m_RootNodes;
	/**
	* Maps the name of the bone to the bone itself.
	*/
	map<tstring,SkeletonNode*> m_NodeMap;
	/**
	* The world transform for the skeleton.
	*/
	Transform * m_World;
	/**
	* The current animation object for this skeleton.
	*/
	Animation* m_pAnimation;
	/**
	* The map with the animations for this skeleton.
	*/
	map<tstring,AnimationPtr> m_Animations;
	/**
	* The start of the animation.
	*/
	unsigned int m_AnimationStart;
	/**
	* Storage for all the bone matrices.
	*/
	float * m_BoneMatrices;
	/**
	*
	*/
	float m_AnimationTime;
	/**
	*
	*/
	bool m_DebugVisualCreated;
	/**
	* Indicates that the current animation is looping.
	*/
	bool m_Looping;
	/**
	* State variable to enable lazy calculation of local transforms.
	*/
	bool m_LocalTransformsCreated;
	// -------------------------
	// Disabling default copy constructor and default assignment operator.
	// If you get a linker error from one of these functions, your class is internally trying to use them. This is
	// an error in your class, these declarations are deliberately made without implementation because they should never be used.
	// -------------------------
	Skeleton(const Skeleton& t);
	Skeleton& operator=(const Skeleton& t);
};
